
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
from direct.gui.DirectGui import *
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import *
from pandac.PandaModules import Camera
from panda3d.physx import *
from direct.task import Task
import sys

class NetworkedPlayer():
    def __init__(self,id):
        self.name ="Default"
        self.id = id
        self.pos = Vec3(0,0,0)
        self.hpr = Vec3(0,0,0)
        self.oldpos = Vec3(0,0,0)
        self.hp = 100
        self.team = 0
        shapeDesc = PhysxBoxShapeDesc()
        shapeDesc.setDimensions(Vec3(0.3,0.3,1.5))
        bodyDesc = PhysxBodyDesc()
        bodyDesc.setMass(50.0)
        #shapeDesc.setTrigger(True)
        actorDesc = PhysxActorDesc()
        actorDesc.setBody(bodyDesc)
        actorDesc.setName(self.id)
        actorDesc.addShape(shapeDesc)
        self.body = base.Physics1.scene.createActor(actorDesc)
        self.body.setBodyFlag(11,True)
#        self.body.get_Actor().
    def Draw(self):
        self.model=Actor()
        self.model.loadModel("models/tron")
        self.model.loadAnims({"running":"models/tron_anim"})
        self.model.reparentTo(render)
        self.model.setScale(0.08,0.08,0.08)
        self.isRunning=False
    def Update(self):
        if self.isRunning:
            self.model.loop("running")
        else:
            self.model.stop()
            self.model.pose("running", 0)
        print self.pos
        print self.oldpos
        if self.pos != self.oldpos:
            self.isRunning = True
        else:
            self.isRunning = False
        if self.hp <= 0:
            self.model.hide()
            self.body.setActorFlag(1,True)
        else:
            self.model.show
            self.body.setActorFlag(1,False)
        self.model.setPos(self.pos + Vec3(0,0,-0.5))
        self.body.setGlobalPos(Point3(self.pos))
        self.body.setGlobalHpr(self.hpr[0]+-100,0,0)
        self.model.setHpr(self.hpr[0]+-100,0,0)
        self.oldpos = self.pos

class Client():
    def __init__(self,ip):
        self.target = NetAddress()
        self.target.setHost(ip,35167)
        self.Clients = 0
        self.ClientList = {}
        self.remainTime = 0
        self.Retrys = 0
        self.initNetwork()

    def initNetwork(self):
        self.cManager = ConnectionManager()
        self.cWriter = ConnectionWriter(self.cManager,0)
        self.cReader = QueuedConnectionReader(self.cManager, 0)
        self.connect()
    def connect(self):
        self.Connection = self.cManager.openUDPConnection(35168)
        self.cReader.addConnection(self.Connection)
        base.taskMgr.doMethodLater(0.2, self.writeTask, 'Write')
        base.taskMgr.doMethodLater(0.2,self.readTask, "Read")
    def CheckPlayers(self,task):
        for i in self.ClientList:
            self.ClientList[i].Update()
    def NewRound(self,winner,pos):
        print winner
        if base.Player1.team == 0:#NOTE --- Forseeable problems this method needs expansion on server and client. 0 is ct
            position = Point3(base.MapSpawnsCT[pos].getPos()+Point3(0,0,5))
            base.Physics1.controller.setPos(Point3(position))
        else:
            position = Point3(base.MapSpawnsT[pos].getPos()+Point3(0,0,5))
            base.Physics1.controller.setPos(Point3(position))
        base.Player1.hp = 100

    def readTask(self,task):
        while self.cReader.dataAvailable():
            datagram = NetDatagram()
            if self.cReader.getData(datagram):
                #sender = datagram.getAddress()
                message = PyDatagramIterator(datagram)
                self.Clients = message.getUint8()
                for i in range(self.Clients):
                    id = message.getString()
                    if id == "HIT":
                        code = message.getUint8()
                        if code == 1:
                            base.Player1.hp -= message.getFloat32()
                        return Task.cont
                    elif id == "CONNECT":
                        code = message.getUint8()
                        if code == 10:
                            self.ping = message.getFloat32() - self.oldTime
                            print self.ping
                        return Task.cont
                    elif id == "NEW":
                        code = message.getUint8()
                        if code == 3:
                            lastwinner = message.getString()
                            position = message.getUint8()
                            self.NewRound(lastwinner,position)
                    elif id not in self.ClientList:
                        self.ClientList[id] = NetworkedPlayer(id)
                        self.ClientList[id].Draw()
                    code = message.getUint8()
                    if code == 0:
                        try:
                            player = self.ClientList[id]
                            player.team = message.getUint16()
                            x = message.getFloat32()
                            y = message.getFloat32()
                            z = message.getFloat32()
                            player.pos = Vec3(x,y,z)
                            h = message.getFloat32()
                            p = message.getFloat32()
                            r = message.getFloat32()
                            player.hpr = Vec3(h,p,r)
                            player.hp = message.getFloat32()
                            self.remainTime = message.getFloat32()
                            player.name = message.getString()
                        except:
                            print sys.exc_info()
                    if code == 4:
                        self.ClientList[id].model.cleanup()
                        del self.ClientList[id].body
                        del self.ClientList[id]
        return Task.cont

    def writeTask(self,task,who=0):
        package = PyDatagram()
        if task == "HIT":
            package.addInt16(1)
            package.addString(who)
            package.addInt16(base.Player1.gunlist[base.Player1.equip[base.Player1.current]].damage)
        else:
            package.addInt16(0)
            package.addInt16(base.Player1.team)
            package.addFloat32(base.Player1.dummy.getPos().getX())
            package.addFloat32(base.Player1.dummy.getPos().getY())
            package.addFloat32(base.Player1.dummy.getPos().getZ())
            package.addFloat32(base.Player1.dummy.getH())
            package.addFloat32(base.Player1.dummy.getP())
            package.addFloat32(base.Player1.dummy.getR())
            package.addFloat32(base.Player1.hp)
            package.addString(base.Player1.name)
        self.cWriter.send(package,self.Connection,self.target)
        return Task.cont
